import time, datetime, traceback
from xtquant.xttrader import  XtQuantTraderCallback
from xtquant import xtconstant
import requests
from typing import List
from 基础配置 import settings
from 组件.notice import show_notification_thread, init_notification_system
from 订单监控 import order_watch
import threading
from 公共函数 import get_stock_all



class MyXtQuantTraderCallback(XtQuantTraderCallback):
    def __init__(self,trader, acc,xt_trader):  # 新增构造函数
        super().__init__()
        self.acc = acc  # 保存交易接口实例
        self.trader = trader
        self.xt_trader = xt_trader  # 保存交易接口实例
        self.order_status = {}  # 记录委托状态：{order_id: {"total_volume": 委托总量, "filled_volume": 已成交量}}
        self.stock_type = {stock["all_code"]: stock["name"] for stock in settings.STOCK_CODE}
        self._lock = threading.Lock()  # 新增锁

    ##系统
    ##初始化
    def on_start(self):
        ##1.获取未成交订单
        wait_orders = self.get_orders()[1]
        ##2.插入到order_status中
        for order in wait_orders:
            self.order_status[order.order_sysid] = {
                "total_volume": order.order_volume,
                "filled_volume": 0,
                "stock_code": order.stock_code,
                "direction": order.direction,
            }
        print(f"初始化完成,当前挂单列表:{self.order_status}")
    ##连接断开
    def on_disconnected(self):
        print(datetime.datetime.now(), '连接断开')
        show_notification_thread("系统", "连接断开")

    ##交易
    ##成交回调
    def on_stock_trade(self, trade):
        """成交回调（检查是否完全成交）"""
        order_id = trade.order_sysid
        stock_span = {stock["all_code"]: stock["span"] for stock in settings.STOCK_CODE}
        span = stock_span.get(trade.stock_code)
        stock_name = self.stock_type.get(trade.stock_code)
        if order_id not in self.order_status:
            return
        # 更新已成交量
        self.order_status[order_id]["filled_volume"] += trade.traded_volume
        # 检查是否完全成交
        status = self.order_status[order_id]
        if status["filled_volume"] >= status["total_volume"]:
            direction = ""
            print(
                f"[完全成交] 委托单: {order_id}, "
                f"股票: {status['stock_code']}, "
                f"方向: {status['direction']}, "
                f"总量: {status['total_volume']}, "
                f"成交价: {trade.traded_price},"
                f"备注: {trade.order_remark}"
            )
            # 判断原方向并挂反手单
            fanshou = True
            # if trade.order_remark == "自动平仓":
            #     print("自动平仓不挂反手单")
            #     fanshou = False
            #

            if fanshou:
                if trade.order_type == 23:  # 原方向为买入，则反手卖出
                    direction = "买入"
                    price = float(trade.traded_price) + float(span)
                    self.place_reverse_order(
                        stock_code=status['stock_code'],
                        price=price,  # 市价单（或指定价格）
                        volume=status['total_volume'],
                        direction=xtconstant.STOCK_SELL,  # 卖出
                        order_remark="反手卖出"
                    )
                elif trade.order_type == 24:  # 原方向为卖出，则反手买入
                    if status['stock_code'] != "513130.SH":
                        print("再次反手单不挂买入")
                    else:
                        direction = "卖出"
                        price = float(trade.traded_price) - float(span)
                        self.place_reverse_order(
                            stock_code=status['stock_code'],
                            price=price,  # 市价单（或指定价格）
                            volume=status['total_volume'],
                            direction=xtconstant.STOCK_BUY,  # 买入
                            order_remark="反手买入"
                        )
            # 移除已完成的委托
            title = f"委托单{order_id}成交"
            msg = f"{stock_name}{direction}成交,数量{status['total_volume']}"
            show_notification_thread(title, msg)
            self.order_status.pop(order_id)

    ##挂单
    ##查询
    def get_orders(self):
        # 查询当前账户的所有委托单
        # self.trader.log_callback("查询当前账户的所有委托单")
        orders = self.xt_trader.query_stock_orders(self.acc)
        # 筛选已成交的委托单（根据状态字段）
        filled_orders = [
            order for order in orders
            if order.order_status in [56]  # 已经成交
        ]

        no_filled_orders = [
            order for order in orders
            if order.order_status in [50]  # 待成交
        ]
        # 按 order_time 升序排序（从早到晚）
        filled_orders_sorted = sorted(filled_orders, key=lambda x: x.order_time, reverse=True)

        for order in filled_orders_sorted:
            dt = datetime.datetime.fromtimestamp(order.order_time)
            formatted_time = dt.strftime("%Y-%m-%d %H:%M:%S")
            # print(f"原始id: {order.order_sysid}")
            # print(f"股票编号: {order.stock_code}")
            # print(f"成交价格: {order.traded_price}")
            # print(f"方向: {order.order_type}")
            # print(f"数量: {order.traded_volume}")
            # print(f"报单时间: {formatted_time}")
            # print(f"----------------------------------")
        stocks = get_stock_all()
        return filled_orders_sorted,no_filled_orders,stocks
    ##普通下单
    def place_reverse_order(self, stock_code, price, volume, direction, order_remark):
        try:
            order_id = self.xt_trader.order_stock_async(self.acc, stock_code, direction, volume,xtconstant.FIX_PRICE, price, '策略名称', order_remark)
            print(f"订单已提交，委托ID: {order_id}")
            return order_id
        except Exception as e:
            print(f"挂单失败: {e}")
            show_notification_thread("交易", "挂单失败")
            traceback.print_exc()

    ##市价下单【迅投市价,存在滑点】
    def place_market_order2(self, stock_code, volume, direction, order_remark):
        try:
            ##如果有相同股票的待买入挂单则不买入
            # 获取当前待成交订单
            _, no_filled_orders, _ = self.get_orders()

            # 检查是否有相同股票的待买入挂单（只检查买入单）
            for order in no_filled_orders:
                if order.stock_code == stock_code and order.direction == xtconstant.STOCK_BUY:
                    if self.trader and self.trader.log_callback:
                        self.trader.log_callback(f"股票 {stock_code} 已有待成交买入挂单，跳过买入")
                    return False

            # 如果没有相同股票的待买入挂单，则继续下单
            order_id = self.xt_trader.order_stock_async(self.acc, stock_code, direction, volume,
                                                        xtconstant.LATEST_PRICE, 0, order_remark, "市价")
            if self.trader and self.trader.log_callback:
                self.trader.log_callback(f"市价单提交成功: {stock_code}, 数量 {volume}, ID {order_id}")
            return order_id
        except Exception as e:
            if self.trader and self.trader.log_callback:
                self.trader.log_callback(f"市价单提交失败: {e}")
            traceback.print_exc()
            return False

    ##市价下单2【卖一价格限价单】
    def place_market_order(self, stock_code, volume, direction, order_remark):
        try:
            ##如果有相同股票的待买入挂单则不买入
            # 获取当前待成交订单
            _, no_filled_orders, _ = self.get_orders()

            # 检查是否有相同股票的待买入挂单（只检查买入单）
            for order in no_filled_orders:
                ##这里判断是否是1笔转还是一直挂单
                ##if order.stock_code == stock_code and order.direction == xtconstant.STOCK_BUY:
                if order.stock_code == stock_code:
                    if self.trader and self.trader.log_callback:
                        self.trader.log_callback(f"股票 {stock_code} 已有待成交买入挂单，跳过买入")
                    return False
            
            ##获取股票当前的价格
            try:
                # 使用xtdata获取股票当前价格
                from xtquant import xtdata
                # 获取最新tick数据
                tick_data = xtdata.get_full_tick([stock_code])
                
                # 安全地获取价格数据
                current_price = 0
                if stock_code in tick_data:
                    stock_data = tick_data[stock_code]
                    
                    # 检查数据结构并安全获取价格
                    if isinstance(stock_data, dict):
                        # 如果返回的是字典格式
                        current_price = stock_data.get('lastPrice', 0)
                    elif isinstance(stock_data, list) and len(stock_data) > 0:
                        # 如果返回的是列表格式
                        if isinstance(stock_data[0], dict):
                            current_price = stock_data[0].get('lastPrice', 0)
                        else:
                            current_price = stock_data[0] if stock_data[0] else 0
                
                if current_price > 0:
                    # 根据买入/卖出方向设置价格
                    if direction == xtconstant.STOCK_BUY:
                        # 买入：当前价格+0.001（确保能成交）
                        price = current_price + 0.001
                    else:
                        # 卖出：当前价格-0.001（确保能成交）
                        price = current_price - 0.001
                else:
                    # 如果获取不到价格，使用市价单
                    print(f"无法获取股票 {stock_code} 当前价格，使用市价单")
                    return self.place_market_order2(stock_code, volume, direction, order_remark)
                    
            except Exception as e:
                # 如果获取价格失败，使用市价单
                print(f"获取价格失败: {e}")
                return self.place_market_order2(stock_code, volume, direction, order_remark)
            
            # 如果没有相同股票的待买入挂单，则继续下单
            order_id = self.place_reverse_order(
                stock_code=stock_code,
                price=price,  # 使用计算出的价格
                volume=volume,
                direction=direction,
                order_remark=order_remark
            )
            if self.trader and self.trader.log_callback:
                self.trader.log_callback(f"限价单提交成功: {stock_code}, 数量 {volume}, 价格 {price}, ID {order_id}")
            return order_id
        except Exception as e:
            if self.trader and self.trader.log_callback:
                self.trader.log_callback(f"限价单提交失败: {e}")
            traceback.print_exc()
            return False
    ##平仓下单
    def modify_to_market_order(self, order_sysid):
        try:
            # 1. 先获取原委托信息（在撤单之前）
            orders = self.get_orders()[1]
            original_order = None
            for order in orders:
                if order.order_sysid == order_sysid:
                    original_order = order
                    break

            if not original_order:
                self.trader.log_callback(f"未找到委托单，order_sysid: {order_sysid}")
                show_notification_thread("交易", f"平仓失败：未找到委托单 {order_sysid}")
                return False

            # 2. 保存原委托信息
            stock_code = original_order.stock_code
            volume = original_order.order_volume - original_order.traded_volume  # 使用未成交数量
            order_remark = "自动平仓"
            direction = xtconstant.STOCK_SELL if original_order.order_type == 24 else xtconstant.STOCK_BUY

            self.trader.log_callback(f"开始平仓流程 原始ID:{order_sysid} {stock_code} 方向:{direction} 数量:{volume}")

            # 3. 撤掉原委托
            market = xtconstant.SH_MARKET if stock_code.startswith('60') else xtconstant.SZ_MARKET
            cancel_result = self.xt_trader.cancel_order_stock_sysid(
                account=self.acc,
                market=market,
                sysid=order_sysid
            )

            if cancel_result == -1:
                self.trader.log_callback(f"撤单失败，order_sysid: {order_sysid}")
                show_notification_thread("交易", f"平仓失败：撤单失败 {order_sysid}")
                return False

            # 4. 轮询检查撤单是否完成（最多等待3秒）
            max_wait_time = 3  # 秒
            check_interval = 0.3  # 检查间隔
            start_time = time.time()

            while time.time() - start_time < max_wait_time:
                # 检查委托状态
                orders = self.get_orders()[1]
                order_exists = any(order.order_sysid == order_sysid for order in orders)

                if not order_exists:
                    # 5. 确认撤单成功后，提交新的市价单
                    order_id = self.place_market_order(stock_code, volume, direction, order_remark)
                    if order_id:
                        self.trader.log_callback(f"平仓成功 新委托ID:{order_id} {stock_code} {direction} {volume}")
                        show_notification_thread("交易", f"平仓成功 新单号:{order_id}")
                        return order_id
                    else:
                        self.trader.log_callback(f"平仓下单失败 {stock_code} {direction} {volume}")
                        show_notification_thread("交易", f"平仓下单失败")
                        return False

                time.sleep(check_interval)

            # 超时处理
            self.trader.log_callback(f"平仓超时：撤单状态未确认 {order_sysid}")
            show_notification_thread("交易", f"平仓超时：撤单未完成 {order_sysid}")
            return False

        except Exception as e:
            error_msg = f"平仓异常: {str(e)}"
            self.trader.log_callback(error_msg)
            show_notification_thread("交易", error_msg)
            traceback.print_exc()
            return False
    
    ##按照股票代码平仓所有卖单
    def cancel_all_sell_orders(self, stock_code):
        if stock_code == "513120.SH":
            print("创新药执行平仓")
            orders = self.get_orders()[1]
            for order in orders:
                if order.stock_code == stock_code and order.direction == xtconstant.STOCK_SELL:
                    self.modify_to_market_order(order.order_sysid)
                
    ##异步撤单
    def cancel_order(self,order_sysid):
        self.xt_trader.cancel_order_stock_sysid_async(self.acc, xtconstant.SH_MARKET, order_sysid)
    ##下单完成推送
    def on_stock_order(self, order):
        print(
            f"------------订单信息-------------"
            f"[下单] : {order.order_sysid}, "
            f"股票: {order.stock_code}, "
            f"方向: {order.order_type}, "
            f"总量: {order.order_volume}, "
            f"委托价: {order.price}"
            f"状态: {order.order_status}"
            f"------------订单信息-------------"
        )

        if order.order_status == 50:
            self.order_status[order.order_sysid] = {
                "total_volume": order.order_volume,
                "filled_volume": 0,
                "stock_code": order.stock_code,
                "direction": order.direction,
            }
            print(f"已挂单{order.order_sysid}")
            print(self.order_status)
            print("--------------------------------------------------")
        if order.order_status == 54:
            self.order_status.pop(order.order_sysid)
            print(f"已撤单{order.order_sysid}")
            print(self.order_status)
            print("--------------------------------------------------")
    ##下单报错
    def on_order_error(self, order_error):
        ##show_notification_thread("交易", "委托报错回调")
        self.trader.log_callback(f"委托报错回调 {order_error.order_remark} {order_error.error_msg}")
    ##订单检测
    def look_orders(self):
        order_watch(self)

    ##保存
    ##转换数据源
    def convert_to_test_order_create(self, order) -> dict:
        """将迅投订单格式转换为API需要的格式"""
        dt = datetime.datetime.fromtimestamp(order.order_time)
        formatted_time = dt.strftime("%Y-%m-%d %H:%M:%S")

        return {
            "cod": order.stock_code.split('.')[0],
            "val": float(order.traded_price),
            "cnt": int(order.traded_volume),
            "dir": "买" if order.order_type == 23 else "卖",
            "dte": formatted_time,
            "sid": 0,  # 默认没有关联ID
            "flg": "未关联",
            "jlr": 0,
            "cje": float(order.traded_price)*float(order.traded_volume),
            "fse": float(order.traded_price)*float(order.traded_volume),
            "ghf":0.00,
            "sxf":0.00,
            "yhs": 0.00,
            # 其他必要字段...
        }
    ##保存订单至本地
    def save_orders(self):
        """获取并保存订单到远程数据库"""
        orders = self.get_orders()[0]
        if not orders:
            self.trader.log_callback("没有需要保存的订单")
            return False
        # 转换订单格式
        orders_to_send = [self.convert_to_test_order_create(order) for order in orders]
        # 发送到API
        success = self.send_orders_to_api(orders_to_send)
        if success:
            msg = f"成功保存了{len(orders_to_send)}条订单"
            self.trader.log_callback(msg)
            show_notification_thread("订单", msg)

        else:
            self.trader.log_callback("保存订单失败")

        return success
    ##发送订单数据
    def send_orders_to_api(self, orders: List[dict]) -> bool:
        """发送订单数据到远程API（同步版本）"""
        api_url = settings.API
        headers = {"Content-Type": "application/json"}

        try:
            response = requests.post(api_url, json=orders, headers=headers)
            if response.status_code == 200:
                result = response.json()
                return result.get("code", 400) == 200
            return False
        except requests.exceptions.RequestException as e:
            print(f"API请求错误: {e}")
            return False
        except ValueError as e:
            print(f"JSON解析错误: {e}")
            return False

    ##其他
    ##获取最后一笔订单
    def get_last_trade(self):
        trades = self.xt_trader.query_stock_trades(self.acc)
        if trades:
            stock_name = self.stock_type.get(trades[-1].stock_code)
            msg = f"[最新成交]: {stock_name} {trades[-1].traded_price} {trades[-1].traded_volume} {trades[-1].direction} {trades[-1].traded_time} {trades[-1].order_id} {trades[-1].traded_id} {trades[-1].order_type}"
            print(msg)
            self.trader.log_callback(msg)
        else:
            msg = "暂无成交订单"
            print(msg)
            self.trader.log_callback(msg)
    ##关闭
    def cleanup(self):
        # 关闭交易连接等清理工作
        if hasattr(self, 'xt_trader'):
            self.xt_trader.stop()